package com._21cn.framework.http;

import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * HttpRequestInfo 对http Request进行进一步的封装，方便调用
 */
public class HttpRequestInfo {
	protected String ipHeaderName = null;	//remoteIP是通过指定的http头传递的
	protected HttpServletRequest request;
	private final String url;
	private final Cookie[] cookies;
	private String urlHostPrefix;
	private String userIp = null;
	private Properties headers = null;
	private Map<String,Object> attributes = null;
	private Map<String,Object> sessions = null;
	private Map<String,Object> contextAttributes = null;
	private Map<String,Object> contextInitParameters = null;
	private Properties parameters = null;
	private boolean cleanScript = true;
	
	/**
	 * 构造函数
	 * @param request http请求对象
	 */
	public HttpRequestInfo( HttpServletRequest request ){
		this.request = request;
		url = request.getRequestURI() + (request.getQueryString()!=null?"?"+request.getQueryString():"");
		cookies = request.getCookies();
	}
	
	public HttpRequestInfo( HttpServletRequest request, boolean cleanJavascript ){
		this( request );
		this.cleanScript= cleanJavascript;
	}

    /**
     * 获取请求的应用的完整的URL
     * @param request HTTP请求对象
     * @return 请求的应用的完整的URL
     */
    public static String getAppURL(HttpServletRequest request) {
        StringBuffer url = new StringBuffer();
        url.append( getUrlHostPrefix( request ) );
        url.append(request.getContextPath());
        return url.toString();
    }

    /**
     * 获取请求的URL的host和port部分
     * @param request HTTP请求对象
     * @return 如：http://www.host.com:8080,或https://www.host.com:8080
     */
    public static String getUrlHostPrefix(HttpServletRequest request) {
        StringBuffer url = new StringBuffer();
    	int port = request.getServerPort();
        if (port < 0) {
            port = 80; // Work around java.net.URL bug
        }
        String scheme = request.getScheme();
        url.append(scheme);
        url.append("://");
        url.append(request.getServerName());
        if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) {
            url.append(':');
            url.append(port);
        }
        return url.toString();
    }
	
	/**
	 * 获取用户端的ip地址，如果经过CDN,或proxy，通常用户端的ip地址是在http头信息中，目前支持X-Forwarded-For，
	 * X-Real-IP，Cdn-Src-Ip，Proxy-Client-IP，WL-Proxy-Client-IP等头信息
	 * @param request http请求对象
	 * @return 用户端的ip地址
	 */
	public static String getUserIp(HttpServletRequest request){
		String ip = request.getHeader("Cdn-Src-Ip");
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Forwarded-For");
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Real-IP");
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		if(ip.indexOf(",") > -1){
			ip = ip.substring(0,ip.indexOf(","));
		}
		return ip;		
	}
	
	public String toString(){
		return new StringBuffer("url:").append(url).append(",userIp:").append(userIp)
		.append(",cookies:").append(cookies).append(",headers:").append(getHeaders())
		.append(",parameters:").append(getParameters()).append(",attributes:").append(getAttributes()).toString();
	}
	
	/**
	 * 获取指定的参数的值，如果没有相关参数则返回默认值
	 * @param name 参数名
	 * @param defaultValue 默认值
	 * @return 指定的参数的值
	 */
	public String getParameter( String name, String defaultValue ){
		String value= request.getParameter( name );
		return ( value != null && value.trim().length()>0 ) ? value: defaultValue;
	}

	/**
	 * 获取指定的参数的值，如果没有相关参数则返回null
	 * @param name 参数名
	 * @return 指定的参数的值
	 */
	public String getParameter( String name ){
		return getParameter( name, null );
	}
	
	/**
	 * 获取指定头信息的值，如果没有相关头信息则返回默认值
	 * @param name 头信息名
	 * @param defaultValue 默认值
	 * @return 指定头信息的值
	 */
	public String getHeader( String name, String defaultValue ){
		String value= request.getHeader( name );
		if ( value != null && value.trim().length()>0 ){
			if( cleanScript ){
				value.toLowerCase().replaceAll( "<script.*</script>", "" );
			}
			return value;
		}
		return defaultValue;
	}

	/**
	 * 获取指定头信息的值，如果没有相关头信息则返回null
	 * @param name 头信息名
	 * @return 指定头信息的值
	 */
	public String getHeader( String name ){
		return getHeader( name, null );
	}
	
	/**
	 * 获取指定的参数的整型值，如果没有相关参数或参数错误则返回0
	 * @param name 参数名
	 * @return 指定的参数的值
	 */
	public int getIntParameter( String name ){
		return getIntParameter( name, 0 );
	}
	
	/**
	 * 获取指定的参数的整型值，如果没有相关参数则返回默认值
	 * @param name 参数名
	 * @param defaultValue 默认值
	 * @return 指定的参数的值
	 */
	public int getIntParameter( String name, int defaultValue ){
		return convertInt( request.getParameter( name ), defaultValue );
	}
	
	/**
	 * 获取指定的属性的整型值，如果没有相关属性或发生错误则返回0
	 * @param name 属性名
	 * @return 指定的属性的值
	 */
	public int getIntAttribute( String name ){
		return getIntAttribute( name, 0 );
	}
	
	/**
	 * 获取指定的属性的整型值，如果没有相关属性或发生错误则返回默认值
	 * @param name 属性名
	 * @param defaultValue 默认值
	 * @return 指定的属性的值
	 */
	public int getIntAttribute( String name, int defaultValue ){
		Object value= request.getAttribute( name );
		return value==null ? defaultValue : convertInt( value.toString(), defaultValue );
	}
	
	/**
	 * 获取指定的属性的字符串型值，如果没有相关属性或发生错误则返回默认值
	 * @param name 属性名
	 * @param defaultValue 默认值
	 * @return 指定的属性的值
	 */
	public String getStringAttribute( String name, String defaultValue ){
		Object value= request.getAttribute( name );
		return ( value != null && value.toString().length()>0 ) ? value.toString(): defaultValue;
	}

	/**
	 * 获取指定的参数的长整型值，如果没有相关参数或参数错误则返回0
	 * @param name 参数名
	 * @return 指定的参数的值
	 */
	public long getLongParameter( String name ){
		return getLongParameter( name, 0 );
	}
	
	/**
	 * 获取指定的参数的长整型值，如果没有相关参数或参数错误则返回默认值
	 * @param name 参数名
	 * @param defaultValue 默认值
	 * @return 指定的参数的值
	 */
	public long getLongParameter( String name, long defaultValue ){
		return convertLong( request.getParameter( name ), defaultValue );
	}

	/**
	 * 获取指定的参数的长整型值，如果没有相关参数或参数错误则返回0
	 * @param name 参数名
	 * @return 指定的参数的值
	 */
	public float getFloatParameter( String name ){
		return getFloatParameter( name, 0.0f );
	}
	
	/**
	 * 获取指定的参数的浮点型值，如果没有相关参数或参数错误则返回默认值
	 * @param name 参数名
	 * @param defaultValue 默认值
	 * @return 指定的参数的值
	 */
	public float getFloatParameter( String name, float defaultValue ){
		return convertFloat( request.getParameter( name ), defaultValue );
	}

	/**
	 * 获取指定的参数的日期型值，如果没有相关参数或参数错误则返回null
	 * @param name 参数名
	 * @param dateFormat 日期格式
	 * @return 指定的参数的值
	 */
	public Date getDateParameter( String name, String dateFormat ){
		return getDateParameter( name, dateFormat, null );
	}
	
	/**
	 * 获取指定的参数的日期型值，如果没有相关参数或参数错误则返回默认值
	 * @param name 参数名
	 * @param dateFormat 日期格式
	 * @param defaultValue 默认值
	 * @return 指定的参数的值
	 */
	public Date getDateParameter( String name, String dateFormat, Date defaultValue ){
		return convertDate( request.getParameter( name ),dateFormat, defaultValue );
	}
	
	/**
	 * 获取指定头信息的整型值，如果没有相关头信息则返回0
	 * @param name 头信息名
	 * @return 指定头信息的值
	 */
	public int getIntHeader( String name ){
		return convertInt( request.getHeader( name ), 0 );
	}

	/**
	 * 获取指定头信息的整型值，如果没有相关头信息则返回默认值
	 * @param name 头信息名
	 * @param defaultValue 默认值
	 * @return 指定头信息的值
	 */
	public int getIntHeader( String name, int defaultValue ){
		return convertInt( request.getHeader( name ), defaultValue );
	}
	
	/**
	 * 获取指定头信息的日期型值，如果没有相关头信息或参数错误则返回null
	 * @param name 头信息名
	 * @param dateFormat 日期格式
	 * @return 指定头信息的值
	 */
	public Date getDateHeader( String name, String dateFormat ){
		return getDateHeader( name, dateFormat, null );
	}
	
	/**
	 * 获取指定头信息的日期型值，如果没有相关头信息或参数错误则返回默认值
	 * @param name 头信息名
	 * @param dateFormat 日期格式
	 * @param defaultValue 默认值
	 * @return 指定头信息的值
	 */
	public Date getDateHeader( String name, String dateFormat, Date defaultValue ){
		return convertDate( request.getHeader( name ),dateFormat, defaultValue );
	}

	
	/**
	 * 获取指定名称的cookie
	 * @param cookieName 指定的cookie名称
	 * @return 指定名称的cookie
	 */
	public Cookie getCookie( String cookieName ){
		if( cookies == null ) return null;
		for( int i=0; i<cookies.length; i++ ){
			if( cookies[i].getName().equals( cookieName ) )
				return cookies[i];
		}
		return null;
	}

	/**
	 * 获取指定名称的cookie
	 * @param cookieName 指定的cookie名称
	 * @param defaultValue 默认值
	 * @return 指定名称的cookie
	 */
	public String getCookieValue( String cookieName, String defaultValue ){
		Cookie c = getCookie( cookieName );
		if( c == null )
			return defaultValue;
		String value = c.getValue();
		return ( value != null && value.trim().length()>0 ) ? value: defaultValue;
	}

	/**
	 * 获取指定名称的cookie
	 * @param cookieName 指定的cookie名称
	 * @param defaultValue 默认值
	 * @return 指定名称的cookie
	 */
	public int getCookieIntValue( String cookieName, int defaultValue ){
		Cookie c = getCookie( cookieName );
		if( c == null )
			return defaultValue;
		return convertInt( c.getValue(), defaultValue );
	}

	/**
	 * 获取指定名称的cookie
	 * @param cookieName 指定的cookie名称
	 * @param defaultValue 默认值
	 * @return 指定名称的cookie
	 */
	public long getCookieLongValue( String cookieName, long defaultValue ){
		Cookie c = getCookie( cookieName );
		if( c == null )
			return defaultValue;
		return convertLong( c.getValue(), defaultValue );
	}

	/**
	 * 获取指定名称的cookie
	 * @param cookieName 指定的cookie名称
	 * @param defaultValue 默认值
	 * @return 指定名称的cookie
	 */
	public float getCookieLongValue( String cookieName, float defaultValue ){
		Cookie c = getCookie( cookieName );
		if( c == null )
			return defaultValue;
		return convertFloat( c.getValue(), defaultValue );
	}

	/**
	 * @return 返回 所有的cookie。
	 */
	public Cookie[] getCookies() {
		return cookies;
	}
	
	/**
	 * @return 返回 所有的header。
	 */
    public synchronized Properties getHeaders() {
		if( headers == null ){
			headers = new Properties();
			for( Enumeration<String> names = request.getHeaderNames(); names.hasMoreElements(); ){
				String name = names.nextElement(); 
				headers.setProperty( name, request.getHeader( name ) );
			}
		}
		return headers;
	}
	
	/**
	 * @return 返回 所有的parameter。
	 */
	public synchronized Properties getParameters() {
		if( parameters == null ){
			parameters = new Properties();
			for( Enumeration<String> names = request.getParameterNames(); names.hasMoreElements(); ){
				String name = names.nextElement();
				parameters.setProperty( name, getParameter( name ) );
			}
		}
		return parameters;
	}
	
	/**
	 * @return 返回 所有的attribute。
	 */
	public synchronized Map<String,Object> getAttributes() {
		if( attributes == null ){
			attributes = new HashMap<String,Object>();
			for( Enumeration<String> names = request.getAttributeNames(); names.hasMoreElements(); ){
				String name = names.nextElement(); 
				attributes.put( name, request.getAttribute( name ) );
			}
		}
		return attributes;
	}

	/**
	 * @return 返回 所有的sessions。
	 */
	public synchronized Map<String,Object> getSessions() {
		if( sessions == null ){
			HttpSession session = request.getSession(false);
			sessions = new HashMap<String,Object>();
			if( session == null )
				return sessions;
			for( Enumeration<String> names = session.getAttributeNames(); names.hasMoreElements(); ){
				String name = names.nextElement(); 
				sessions.put( name, session.getAttribute( name ) );
			}
		}
		return sessions;
	}

	/**
	 * @return 返回 所有的contextAttributes。
	 */
	public synchronized Map<String,Object> getContextInitParameters( ServletContext ctx ) {
		if( contextInitParameters == null ){
			contextInitParameters = new HashMap<String,Object>();
			for( Enumeration<String> names = ctx.getInitParameterNames(); names.hasMoreElements(); ){
				String name = names.nextElement(); 
				contextInitParameters.put( name, ctx.getInitParameter( name ) );
			}
		}
		return contextInitParameters;
	}

	/**
	 * @return 返回 所有的contextAttributes。
	 */
	public synchronized Map<String,Object> getContextAttributes( ServletContext ctx ) {
		if( contextAttributes == null ){
			contextAttributes = new HashMap<String,Object>();
			for( Enumeration<String> names = ctx.getAttributeNames(); names.hasMoreElements(); ){
				String name = names.nextElement(); 
				contextAttributes.put( name, ctx.getAttribute( name ) );
			}
		}
		return contextAttributes;
	}

	/**
	 * @return 返回 用户所请求的url。
	 */
	public String getUrl() {
		return url;
	}
	
	/**
	 * 从指定的http头获取用户的ip地址，如果没有有效的http头，将按默认算法获取
	 * @param ipHeaderName
	 * @return 返回 用户端的ip地址。
	 */
	public String getUserIp( String ipHeaderName ){
		if( userIp != null )
			return userIp;
		
		if( !StringUtils.isEmpty( ipHeaderName ) ){
			if( StringUtils.isEmpty( this.ipHeaderName ) )
				this.ipHeaderName = ipHeaderName;
			userIp = getHeader( ipHeaderName, null );
			if( userIp != null )
				return userIp;
		}
		
		if( !StringUtils.isEmpty( this.ipHeaderName ) )
			userIp = getHeader( this.ipHeaderName, getUserIp(request) );
		else
			userIp = getUserIp(request);
		return userIp;
	}

	/**
	 * @return 返回 用户端的ip地址。
	 */
	public synchronized String getUserIp() {
		return getUserIp( "" );
	}
	
	public synchronized String getUrlHostPrefix() {
		if( urlHostPrefix == null )
			urlHostPrefix = getUrlHostPrefix( request );
		return urlHostPrefix;
	}
	
	public String getFullUrl() {
		return urlHostPrefix = getUrlHostPrefix()+ getUrl();
	}
	
	private int convertInt( String value, int defaultValue ){
		try {
			return Integer.parseInt(value);
		} catch (Exception e) {
			return defaultValue;
		}
		
	}
	
	private float convertFloat( String value, float defaultValue ){
		try {
			return Float.parseFloat(value);
		} catch (Exception e) {
			return defaultValue;
		}
	}
	
	private long convertLong( String value, long defaultValue ){
		try {
			return Long.parseLong(value);
		} catch (Exception e) {
			return defaultValue;
		}
	}

	private Date convertDate( String value,  String dateFormat, Date defaultValue ){
		DateFormat df = new SimpleDateFormat( dateFormat );
		try {
			return df.parse( value );
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * @return 返回 原始的http request对象。
	 */
	public HttpServletRequest getRequest() {
		return request;
	}

	
}


